#include "client.h"
#include "dockbar.h"
#include "wmutils.h"
#include "decor.h"
#include "adx.h"

extern Dockbar *dock;
extern Adx *deluxe;

// General routines

void Adx::grabServer()
{
    if (xGrabCount == 0) {
        XGrabServer(dpy);
    }
    xGrabCount ++;
}

void Adx::ungrabServer()
{
    xGrabCount --;
    if (xGrabCount == 0) {
        XUngrabServer(dpy);
        XFlush(dpy);
    }
}

// Client management routines

// Hints

void Client::getMotifHints()
{
}

void Client::getWMHints()
{
    if (xwmhints) {
        XFree(xwmhints);
        xwmhints = NULL;
    }

    xwmhints = XGetWMHints(display(), clientId);
    if (xwmhints) {
        long flags = xwmhints->flags;

        if (flags & WindowGroupHint) {
            groupLeader = xwmhints->window_group;
            qDebug() << "GROUP LEADER" << groupLeader;
        }

        if (flags & IconPixmapHint) {
            int size = 128; // preferred size

            int w, h;
            unsigned char *pixdata = NULL;
            bool foundIcon = false;

            if (Utils::readRGBIcon(display(), clientId, size, size, &w, &h, &pixdata)) {
                QImage im(pixdata, w, h, QImage::Format_ARGB32);
                appIcon = QPixmap::fromImage(im);
                foundIcon = true;
                qDebug() << "found icon (1st method)";
            }
            qDebug() << "read rgb icon w=" << w << "h=" << h;

            // TODO: get KDE icon, if any

            if (!foundIcon) {
                appIcon = QPixmap(":/default/appicon.png");
            }

        }

        // TODO: process extra flags for window input / output
    }

}

void Client::getWMNormalHints(bool update)
{
	XWindowChanges wc;
	unsigned long prevValue;
	if (!xsize) {
	   xsize = XAllocSizeHints();
	}

	long hints = 0;
	if (!XGetWMNormalHints(display(), clientId, xsize, &hints))
		xsize->flags = 0;

	// Set/update gravity
	gravity = xsize->flags & PWinGravity ? xsize->win_gravity : NorthWestGravity;

	// TODO: prevValue
	//prevValue = FLAG_TEST()

	wc.x = client_x;
	wc.y = client_y;
	wc.width = client_w;
	wc.height = client_h;

	if (!(xsize->flags & PMaxSize)) {
		xsize->max_width = INT_MAX;
		xsize->max_height = INT_MAX;
		xsize->flags |= PMaxSize;
	}

	if (!(xsize->flags & PBaseSize)) {
		xsize->base_width = 0;
		xsize->base_height = 0;
	}

	if (!(xsize->flags & PMinSize)) {
		if ((xsize->flags & PBaseSize)) {
			xsize->min_width = xsize->base_width;
			xsize->min_height = xsize->base_height;
		} else {
			xsize->min_width = 1;
			xsize->min_height = 1;
		}
		xsize->flags |= PMinSize;
	}

	if (xsize->flags & PResizeInc) {
		if (xsize->width_inc < 1) {
			xsize->width_inc = 1;
		}
		if (xsize->height_inc < 1) {
			xsize->height_inc = 1;
		}
	} else {
		xsize->width_inc = 1;
		xsize->height_inc = 1;
	}

	if (xsize->flags & PAspect) {
		if (xsize->min_aspect.x < 1)
			xsize->min_aspect.x = 1;
		if (xsize->min_aspect.y < 1)
			xsize->min_aspect.y = 1;

		if (xsize->max_aspect.x < 1)
			xsize->max_aspect.x = 1;
		if (xsize->max_aspect.y < 1)
			xsize->max_aspect.y = 1;
	} else {
		xsize->min_aspect.x = 1;
		xsize->min_aspect.y = 1;
		xsize->max_aspect.x = INT_MAX;
		xsize->max_aspect.y = INT_MAX;
	}

	if (xsize->min_width < 1)
		xsize->min_width = 1;
	if (xsize->min_height < 1)
		xsize->min_height = 1;

	if (xsize->max_width < 1)
		xsize->max_width = 1;
	if (xsize->max_height < 1)
		xsize->max_height = 1;

	if (wc.width > xsize->max_width)
		wc.width = xsize->max_width;
	if (wc.height > xsize->max_height)
		wc.height = xsize->max_height;

	if (wc.width < xsize->min_width)
		wc.width = xsize->min_width;
	if (wc.height < xsize->min_height)
		wc.height = xsize->min_height;

	// TODO: resizeable flag
	// TODO: if (update)

	client_w = wc.width;
	client_h = wc.height;

}

void Client::getWindowHostName()
{/*
	qDebug() << "HOST NAME begin";
	hostName = Atoms::getTextProperty(display(), clientId, Atoms::atom(Atoms::WM_CLIENT_MACHINE));
	qDebug() << "host name = " << hostName;
*/
}

void Client::getWindowName()
{

	char *name;
	Atom type;
	int format;
	unsigned long nitems=0;
	unsigned long extra=0;
	unsigned char *data=NULL;

	clientName = Utils::getUTF8String(display(), clientId, Utils::NET_WM_NAME);
	if (clientName == "")
	{
		clientName = Utils::getTextProperty(display(), clientId, XA_WM_NAME);
	}

	data = NULL;
	XGetWindowProperty(display(), clientId, Utils::atom(Utils::NET_WM_ICON_NAME),
			0, 500, FALSE, AnyPropertyType, &type, &format, &nitems, &extra, &data);

	if (data != NULL) {
			icnName = QString::fromUtf8((char *)data);
			XFree(data);
	} else if (XGetIconName(display(), clientId, &name) && name != NULL) {
			icnName = name;
			XFree(name);
	} else
			icnName = clientName;

	if (titlebar != NULL) titlebar->setTitle(clientName);
	qDebug() << "WINDOW NAME: " << clientName;
    //qDebug() << "ICON NAME:" << icnName;
}

void Client::getAppName(void)
{
    XClassHint c;
    c.res_name = NULL;
    c.res_class = NULL;
    XGetClassHint(display(), clientId, &c);

    if (c.res_class != NULL) {
        appName = QString::fromUtf8((char *)c.res_class);
    } else if (c.res_name != NULL) {
        appName = QString::fromUtf8((char *)c.res_class);
    } else
        appName = clientName;

    XFree(c.res_name);
    XFree(c.res_class);
}



// Transients management

void Client::getTransientFor(Window root, Window *transient)
{
	if (XGetTransientForHint(display(), clientId, transient)) {
		if (*transient == None) {
			*transient = root;
		} else if (*transient == clientId) {
			*transient = None;
		}
	} else {
		*transient = None;
	}
}

bool Client::isTransient()
{
	return (((transientFor != screen_info->xroot) && (transientFor != None) && (transientFor != clientId)) ||
			((transientFor == screen_info->xroot) && (groupLeader != None) && (groupLeader != clientId)));
}

Client *Client::getTransient()
{
	if ((transientFor) && (transientFor != screen_info->xroot)) {
		return deluxe->getClientFromWindow(transientFor);
	}
	return NULL;
}

void Client::getWMProtocols(void)
{
	Atom *protocols;
	int nprot,i;

	protDelete = false;
	protTakeFocus = false;

	if (XGetWMProtocols(display(), clientId, &protocols, &nprot)) {
		for (i=0; i < nprot; i++) {
			if (protocols[i] == Utils::atom(Utils::WM_DELETE_WINDOW)) {
				protDelete = true;
			} else if (protocols[i] == Utils::atom(Utils::WM_TAKE_FOCUS)) {
				protTakeFocus = true;
			}
		}
		XFree(protocols);
	}
}

void Client::setClientState(int state)
{
    ulong data[2];
    data[0] = (ulong)state;
    data[1] = (ulong)None;
	clientState = state;
	XChangeProperty(display(), clientId, Utils::atom(Utils::WM_STATE),
					Utils::atom(Utils::WM_STATE), 32, PropModeReplace, (uchar *)data, 2);
	//qDebug() << "CLIENT STATE =" << clientState;
}

void Client::getColormaps(void)
{
	XWindowAttributes attr;
	XGetWindowAttributes(display(), clientId, &attr);
	colorMap = attr.colormap;
}

void Client::setColormaps(Colormap cmap)
{
	if (cmap== None)
		colorMap = DefaultColormap(display(), DefaultScreen(display()));
	XInstallColormap(display(), colorMap);
}

void Client::resizeRequest(int cx, int cy, int cw, int ch)
{
	if (resizeState)
		return;
    client_w = cw;
    client_h = ch;
	
	n_px = cx;
	n_py = cy+TITLEBAR_HEIGHT+8;

	fixSizes();

    n_pw = client_w;
    n_ph = client_h + TITLEBAR_HEIGHT + 8;

    //move(n_px, n_py);
    resize(n_pw, n_ph);
    XResizeWindow(display(), clientId, client_w, client_h);
	qDebug() << "DONE RESIZE (IN REQUEST) WINDOW";
}

void Client::delayedGrab(int t)
{
	XUngrabKeyboard(display(), CurrentTime);
	keyboardGrabbed = false;
	//QTimer::singleShot(t, this, SLOT(doGrab()));
}

void Client::doGrab()
{
	int ret = 0;
	if (!keyboardGrabbed)
		ret = XGrabKeyboard(display(), clientId, TRUE, GrabModeAsync, GrabModeAsync, CurrentTime);
	if (ret !=0)
		keyboardGrabbed = false;
	else
		keyboardGrabbed = true;
}

// set to active and focus to child
void Client::setChildFocus(WId subwindow, long timestamp)
{
	if (subwindow == 0) XSetInputFocus(display(), clientId, RevertToPointerRoot, CurrentTime);

    if (protTakeFocus) { // WM_TAKE_FOCUS protocol 
		Utils::sendWMProtocols(clientId, Utils::atom(Utils::WM_TAKE_FOCUS), timestamp);
		qDebug() << "PROT. TAKE FOCUS";
	}
	XUngrabKeyboard(display(), CurrentTime);
	keyboardGrabbed = false;
    //QTimer::singleShot(220, this, SLOT(doGrab()));
}
